(import nrc.fuzzy.*)
(import nrc.fuzzy.jess.*)

(load-package FuzzyFunctions)

;defines the linguistic variable
(defglobal ?*SignalStrengthFvar* = (new nrc.fuzzy.FuzzyVariable "SignalStrength" 0.0 100.0 "Percent"))

(deftemplate rss
    "keeps the received signal strength from client"
    (declare (ordered TRUE)))

(deftemplate membership-function
    "a fact representing the interest cell membership function"
    (declare (ordered TRUE)))

(defrule init-calibration
    "Adds the linguistic expressions"
    (declare (salience 100))
    =>
    (?*SignalStrengthFvar* addTerm "None" (new RightLinearFuzzySet 0.0 15.0)) ;0-15
    (?*SignalStrengthFvar* addTerm "Very-Low" (new TriangleFuzzySet 10.0 15.0 45)) ;10-45
    (?*SignalStrengthFvar* addTerm "Low" (new TriangleFuzzySet 40.0 45.0 70.0)) ;40-70
    (?*SignalStrengthFvar* addTerm "Good" (new TriangleFuzzySet 60.0 70.0 85.0)) ;60-85
    (?*SignalStrengthFvar* addTerm "Very-Good" (new TriangleFuzzySet 80.0 85.0 95.0)) ;80-95
    (?*SignalStrengthFvar* addTerm "Excelent" (new LeftLinearFuzzySet 90.0 100.0)) ;90-100
    (store FUZZYVARIABLE ?*SignalStrengthFvar*))

(defrule none
    "establishes membership fuzzy set for fuzzy set None"
    (rss ?ap ?id ?signalStrength&:(fuzzy-match ?signalStrength "None"))
    =>
    (assert
        (membership-function ?ap ?id (new FuzzyValue ?*SignalStrengthFvar* "None"))))

(defrule very-low
    "establishes membership fuzzy set for fuzzy set Very-Low"
    (rss ?ap ?id ?signalStrength&:(fuzzy-match ?signalStrength "Very-Low"))
    =>
    (assert
        (membership-function ?ap ?id (new FuzzyValue ?*SignalStrengthFvar* "Very-Low"))))

(defrule low
    "establishes membership fuzzy set for fuzzy set Low"
    (rss ?ap ?id ?signalStrength&:(fuzzy-match ?signalStrength "Low"))
    =>
    (assert
        (membership-function ?ap ?id (new FuzzyValue ?*SignalStrengthFvar* "Low"))))

(defrule good
    "establishes membership fuzzy set for fuzzy set Good"
    (rss ?ap ?id ?signalStrength&:(fuzzy-match ?signalStrength "Good"))
    =>
    (assert
        (membership-function ?ap ?id (new FuzzyValue ?*SignalStrengthFvar* "Good"))))

(defrule very-good
    "establishes membership fuzzy set for fuzzy set Very-Good"
    (rss ?ap ?id ?signalStrength&:(fuzzy-match ?signalStrength "Very-Good"))
    =>
    (assert
        (membership-function ?ap ?id (new FuzzyValue ?*SignalStrengthFvar* "Very-Good"))))

(defrule excelent
    "establishes membership fuzzy set for fuzzy set Excelent"
    (rss ?ap ?id ?signalStrength&:(fuzzy-match ?signalStrength "Excelent"))
    =>
    (assert
        (membership-function ?ap ?id (new FuzzyValue ?*SignalStrengthFvar* "Excelent"))))

;(defrule calibration-test
;    "tests the calibration process"
;    (declare (salience -100))
;    (membership-function ?ap ?id ?fs)
;    =>
;    (printout t "access point " (?ap toString) " interest point " (?id toString) crlf (?fs plotFuzzyValue "*") crlf)
;    )

(defmodule SIMILARITY)

(import java.util.HashMap)

(defglobal ?*similarity-map* = (new HashMap))


(deftemplate similarity-vector
    "keeps the overall fuzzy similarity of the patterns that matched on the LHS"
    (declare (ordered TRUE)))

(deftemplate user-input
    (declare (ordered TRUE)))

(defrule init-similarity-vector
    ""
    (declare (salience 100))
    (MAIN::membership-function ?ap ?cell-id ?mf)
    =>
    (if (not (?*similarity-map* containsKey ?cell-id))
        then
        (bind ?list (new java.util.ArrayList 3))
        (?list add 0.0)
        (?list add 0.0)
        (?list add 0.0)
        (?*similarity-map* put ?cell-id ?list)
        )
    )

(defrule compute-similarity-vector
    "computes the similarity between the client reading and the interest point fuzzy set"
    (user-input ?ap-id ?value)
    (MAIN::membership-function ?ap ?cell-id ?mf&:(?ap equals ?ap-id)&:(fuzzy-match ?value ?mf))
    =>
    (if (?*similarity-map* containsKey ?cell-id)
        then 
        (bind ?arrayList (?*similarity-map* get ?cell-id))
        (?arrayList set (?ap intValue) (fuzzy-rule-similarity))
        )
    )

(deffunction compute-euclidean-distance (?x ?y ?z)
    "comment"
    (bind ?result (sqrt (+ (** ?x 2) (** ?y 2) (** ?z 2)))
        (return result)))


(defrule compute-nearest-cell
    "computes the nearest cell from client"
    (declare (salience -100))
    =>
    (bind ?temp (new HashMap))
    (bind ?iterator ((?*similarity-map* keySet) iterator))
    (foreach ?key ?iterator
        (bind ?array-list (?*similarity-map* get ?key))
        (bind ?x (?array-list get 0))
        (bind ?y (?array-list get 1))
        (bind ?z (?array-list get 2))
        (bind ?euclidean-point (compute-euclidean-distance ?x ?y ?z))
        (?temp put ?key ?euclidean-point)
        )
    (bind ?max 0.0)
    (bind ?interest-cell null)
    (bind ?it ((?temp keySet) iterator))
    (foreach ?key ?it
        (bind ?value (?temp get ?key))
        (if (> ?value ?max)
            then 
            (bind ?max ?value)
            (bind ?interest-cell-id ?key)
            ))
    (store INTERESTCELL ?interest-cell-id)
    )
